.pc = * "Background routines"

.label tile_data = $a000
.label color_ram = $c000
.label bitmap_ram = $e000
.label background_num_rows = 23

init_background:
{
    // set border to black
    lda #0
    sta $d020

    // set transparent color, background colors 1 & 2
    lda #0
    sta $d021    
    lda #15
    sta $d022
    lda #11
    sta $d023
    
    // initialize camera position
    lda #0
    sta background_origin_x
    sta background_origin_y
    sta background_origin_x_half
    sta background_origin_y_half

    jsr init_tile_lookup
    jsr map_lookup_init
    
    // do a full update
    jsr background_full_update
    rts
}

background_enable:
{
    // set multicolor graphics mode
    lda $d016
    ora #$10
    sta $d016
    lda $d011
    ora #$20
    sta $d011
    
    // select bank 3 ($c000-$ffff) for graphics
    lda $dd00
    and #252
    sta $dd00
    
    // set character RAM location, video RAM location
    lda #[[bitmap_ram & $3fff]/1024 | [[color_ram & $3fff]/1024]*16]
    sta $d018

    rts
}

//////////////////////////////////////////////////

// tile coordinates of the upper-left corner of screen
background_origin_x:
    .byte 0
background_origin_y:
    .byte 0

// half-tile corrections, if the upper-left doesn't correspond to a tile corner
background_origin_x_half:
    .byte 0
background_origin_y_half:
    .byte 0

//////////////////////////////////////////////////

background_full_update:
{
.label column = zero_page_start+35
.label row = zero_page_start+36

    // blank the whole screen
    lda $d011
    and #[255-16]
    sta $d011

    // hide kernel
    lda 1
    and #253
    sta 1
    
    // hide all sprites
    lda #0
    sta $d015

    jsr background_iter_set_upper_left
    lda #20
    sta column
    lda #background_num_rows  
    sta row

    jmp loop1_first
loop1:
    jsr background_iter_down
loop1_first:
    jsr background_fill_character
    dec row
    bne loop1

    jsr background_iter_right
    lda #background_num_rows
    sta row

    jmp loop2_first
loop2:
    jsr background_iter_up
loop2_first:
    jsr background_fill_character
    dec row
    bne loop2

    jsr background_iter_right
    lda #background_num_rows
    sta row
    dec column
    bne loop1_first

    // bring back kernel
    lda 1
    ora #2
    sta 1

    // unblank the screen
    lda $d011
    ora #16
    sta $d011

    rts
}
    
//////////////////////////////////////////////////

.namespace background_iter_state
{
.label tile_ptr = zero_page_start // two bytes
.label tile_x_half = zero_page_start+2
.label tile_y_half = zero_page_start+3
.label bitmap_ptr = zero_page_start+4 // two bytes
.label color_ptr = zero_page_start+6 // two bytes
.label color_ptr_2 = zero_page_start+8 // two bytes    
}

//////////////////////////////////////////////////

background_iter_right:
{
    clc
    lda background_iter_state.bitmap_ptr
    adc #8
    sta background_iter_state.bitmap_ptr
    bcc lblA
    inc background_iter_state.bitmap_ptr+1
lblA:
    inc background_iter_state.color_ptr
    bne lblB
    inc background_iter_state.color_ptr+1
lblB:
    inc background_iter_state.color_ptr_2
    bne lblC
    inc background_iter_state.color_ptr_2+1
lblC:
    lda background_iter_state.tile_x_half
    eor #1
    sta background_iter_state.tile_x_half
    bne done

    inc background_iter_state.tile_ptr
    bne done
    inc background_iter_state.tile_ptr+1
done:
    rts
}
    
//////////////////////////////////////////////////

background_iter_left:
{
    sec
    
    lda background_iter_state.bitmap_ptr
    sbc #8
    sta background_iter_state.bitmap_ptr
    bcs lblA
    dec background_iter_state.bitmap_ptr+1
lblA:
    lda background_iter_state.color_ptr
    bne lblB
    dec background_iter_state.color_ptr+1
lblB:
    dec background_iter_state.color_ptr

    lda background_iter_state.color_ptr_2
    bne lblC
    dec background_iter_state.color_ptr_2+1
lblC:
    dec background_iter_state.color_ptr_2
    
    lda background_iter_state.tile_x_half
    eor #1
    sta background_iter_state.tile_x_half
    beq done

    lda background_iter_state.tile_ptr
    bne lblD
    dec background_iter_state.tile_ptr+1
lblD:
    dec background_iter_state.tile_ptr

done:
    rts
}

//////////////////////////////////////////////////

.macro BackgroundIterDown()
{
    clc
    lda background_iter_state.bitmap_ptr
    adc #64
    sta background_iter_state.bitmap_ptr
    lda background_iter_state.bitmap_ptr+1
    adc #1
    sta background_iter_state.bitmap_ptr+1
    // clc // unnecessary, carry always clear here

    lda background_iter_state.color_ptr
    adc #40
    sta background_iter_state.color_ptr
    bcc lblA
    inc background_iter_state.color_ptr+1
    clc
lblA:
    lda background_iter_state.color_ptr_2
    adc #40
    sta background_iter_state.color_ptr_2
    bcc lblB
    inc background_iter_state.color_ptr_2+1
    clc
lblB:
    lda background_iter_state.tile_y_half
    eor #1
    sta background_iter_state.tile_y_half
    bne done

    lda background_iter_state.tile_ptr
    adc map_width
    sta background_iter_state.tile_ptr    
    bcc done
    inc background_iter_state.tile_ptr+1
done:
}

background_iter_down:
{
    :BackgroundIterDown()
    rts
}

//////////////////////////////////////////////////

.macro BackgroundIterUp()
{
    sec
    lda background_iter_state.bitmap_ptr
    sbc #64
    sta background_iter_state.bitmap_ptr
    lda background_iter_state.bitmap_ptr+1
    sbc #1
    sta background_iter_state.bitmap_ptr+1
    // sec // unnecessary, carry always set

    lda background_iter_state.color_ptr
    sbc #40
    sta background_iter_state.color_ptr
    bcs lblA
    dec background_iter_state.color_ptr+1
    sec
lblA:
    lda background_iter_state.color_ptr_2
    sbc #40
    sta background_iter_state.color_ptr_2
    bcs lblB
    dec background_iter_state.color_ptr_2+1
    sec
lblB:
    lda background_iter_state.tile_y_half
    eor #1
    sta background_iter_state.tile_y_half
    beq done

    lda background_iter_state.tile_ptr
    sbc map_width
    sta background_iter_state.tile_ptr    
    bcs done
    dec background_iter_state.tile_ptr+1
done:
}

background_iter_up:
{
    :BackgroundIterUp()
    rts
}

//////////////////////////////////////////////////
    
background_iter_set_upper_left:
{
    .label tmp_map_width = zero_page_start+30

    lda map_width
    sta tmp_map_width
    
    lda #0
    sta background_iter_state.color_ptr
    sta background_iter_state.color_ptr_2
    sta background_iter_state.bitmap_ptr
    lda #$d8
    sta background_iter_state.color_ptr+1
    lda #>color_ram
    sta background_iter_state.color_ptr_2+1
    lda #>bitmap_ram
    sta background_iter_state.bitmap_ptr+1
    
    lda background_origin_x_half
    sta background_iter_state.tile_x_half
    lda background_origin_y_half
    sta background_iter_state.tile_y_half

    lda #>map_data
    sta background_iter_state.tile_ptr+1
    lda #<map_data
    clc
    ldy background_origin_y
    beq loop_end
loop:
    adc tmp_map_width
    bcc no_carry
    inc background_iter_state.tile_ptr+1
    clc
no_carry:
    dey
    bne loop
loop_end:
    adc background_origin_x
    sta background_iter_state.tile_ptr
    bcc done
    inc background_iter_state.tile_ptr+1
done:
    rts
}

//////////////////////////////////////////////////
    
background_fill_character:
{
.label tile_data_ptr = zero_page_start+32 // two bytes
    
    // look up tile number, compute tile data location
    ldy #0
    lda (background_iter_state.tile_ptr),y
    tax
    lda tile_lookup_lobytes,x
    sta tile_data_ptr
    lda tile_lookup_hibytes,x
    sta tile_data_ptr+1
    
    // copy first color byte
    ldy #32
    lda (tile_data_ptr),y
    ldy #0
    sta (background_iter_state.color_ptr_2),y

    // copy second color byte
    ldy #33
    lda (tile_data_ptr),y
    ldy #0
    sta (background_iter_state.color_ptr),y

    // compute character offset within tile (~11)
    lda #0
    ldx background_iter_state.tile_y_half
    beq no_y_offset
    ora #16
no_y_offset:
    ldx background_iter_state.tile_x_half
    beq no_x_offset
    ora #8
no_x_offset:

    // copy eight bytes of tile data
    clc
    adc tile_data_ptr
    sta tile_data_ptr
    lda tile_data_ptr+1
    adc #0
    sta tile_data_ptr+1
    .for (var i=0;i<8;i++)
    {
        lda (tile_data_ptr),y
        sta (background_iter_state.bitmap_ptr),y
        iny
    }

    rts
}

//////////////////////////////////////////////////

background_scroll_right:
{
    .const AMOUNT=28
    ldx #AMOUNT
loop:    
    lda background_origin_x
    clc
    adc #20
    cmp map_width
    beq done
    
    lda background_origin_x_half
    bne advance_tile
    lda #1
    sta background_origin_x_half
    jmp next
    
advance_tile:
    lda #0
    sta background_origin_x_half
    inc background_origin_x

next:
    dex
    bne loop

done:
    cpx #AMOUNT
    beq no_update
    jsr background_full_update
no_update:
    rts
}
    
//////////////////////////////////////////////////

background_scroll_left:
{
    .const AMOUNT=28
    ldx #AMOUNT
loop:    
    lda background_origin_x_half
    beq advance_tile
    lda #0
    sta background_origin_x_half
    jmp next

advance_tile:
    lda background_origin_x
    beq done
    clc
    adc #$ff
    sta background_origin_x
    lda #1
    sta background_origin_x_half
    jmp next
    
next:
    dex
    bne loop

done:
    cpx #AMOUNT
    beq no_update
    jsr background_full_update
no_update:
    rts
}
    
//////////////////////////////////////////////////
    
background_scroll_down:
{
    .const AMOUNT=22
    ldx #AMOUNT
loop:    
    lda background_origin_y
    clc
    adc #12
    cmp map_height
    beq done
    
    lda background_origin_y_half
    bne advance_tile
    lda #1
    sta background_origin_y_half
    jmp next
    
advance_tile:
    lda #0
    sta background_origin_y_half
    inc background_origin_y

next:
    dex
    bne loop

done:
    cpx #AMOUNT
    beq no_update
    jsr background_full_update
no_update:
    rts
}

//////////////////////////////////////////////////

background_scroll_up:
{
    .const AMOUNT = 22
    ldx #AMOUNT
loop:    
    lda background_origin_y_half
    beq advance_tile
    lda #0
    sta background_origin_y_half
    jmp next

advance_tile:
    lda background_origin_y
    beq done
    clc
    adc #$ff
    sta background_origin_y
    lda #1
    sta background_origin_y_half
    jmp next
    
next:
    dex
    bne loop

done:
    cpx #AMOUNT
    beq no_update
    jsr background_full_update
no_update:
    rts
}

//////////////////////////////////////////////////

.label tile_lookup_lobytes = $400
.label tile_lookup_hibytes = $500
    
init_tile_lookup:
{
    lda #<tile_data
    sta tile_lookup_lobytes
    lda #>tile_data
    sta tile_lookup_hibytes

    ldx #0
loop:
    clc
    lda tile_lookup_lobytes,x
    adc #34
    sta tile_lookup_lobytes+1,x
    lda tile_lookup_hibytes,x
    adc #0
    sta tile_lookup_hibytes+1,x

    inx
    cpx #255
    bne loop

    rts
}
    
/*
.label screen_lookup_table = $c000
.label map_lookup_table = screen_lookup_table+512

screen_lookup_init:
{
    .label screen_pitch = zero_page_start // two bytes

    lda #0
    sta screen_pitch+1
    lda #40
    sta screen_pitch

    lda #0
    sta screen_lookup_table
    sta screen_lookup_table+1

    ldx #0
loop:
    :Add16_X(screen_pitch, screen_lookup_table, screen_lookup_table+2)
    inx
    inx
    txa
    cmp #48
    bne loop

    rts
}
*/
    
//////////////////////////////
    
.label map_lookup_lobytes = $600
.label map_lookup_hibytes = $700

map_lookup_init:
{
    lda #<map_data
    sta map_lookup_lobytes
    lda #>map_data
    sta map_lookup_hibytes

    ldx #1
loop:
    cpx map_height
    beq done

    clc
    lda map_lookup_lobytes-1,x
    adc map_width
    sta map_lookup_lobytes,x
    lda map_lookup_hibytes-1,x
    adc #0
    sta map_lookup_hibytes,x

    inx
    jmp loop

done:    
    rts
}
